<?php

define( 'SUPERC_SCALAR', 3 );
define( 'SUPERC_OBJECT', 3 );
define( 'SUPERC_OBJECT', 3 );

$__superc_types = array ( "NULL"=>0 , "boolean"=>1, "integer"=>2, "double"=>2, "string"=>3, "array"=>4, "object"=>5, "resource"=>6, "unknown"=>7 );
			// N.B. numbers treated as equivalent

$__sc_stack = array();
$__sc_report = false;
$__sc_ignore_spaces = false;
function sc_start() {
	sc_clear(true);
}
function sc_end() {
	sc_clear();
}
function sc_clear($clear_report=false) {
	global $__sc_stack, $__sc_report;
	$__sc_stack = array();
	if ($clear_report) $__sc_report = false;
}
function sc_push($mess) {
	global $__sc_stack;
	array_push($__sc_stack,$mess);
}
function sc_pop() {
	global $__sc_stack;
	array_pop($__sc_stack);
}
function sc_report($mess) {
	global $__sc_stack, $__sc_report;
	//echo "REPORT: $mess \n";
	$__sc_report = implode(" >> ",$__sc_stack) . " : " . $mess;
}
function sc_get_report() {
	global $__sc_report;
	return $__sc_report;
}
function type_index($val) {
	global $__superc_types;
	$type = gettype($val);
	if ( !array_key_exists($type,$__superc_types) )   $type = 'unknown';
	return $__superc_types[$type];
}

function object_compare($arr1,$arr2) {
	sc_start();
	$res = sc_object_compare($arr1,$arr2);
	sc_end();
	return $res;
}

function sc_object_compare($obj1,$obj2) {
	return 0;
}

function array_compare($arr1,$arr2) {
	//echo "array_compare\n";
	//echo "  arr1: ".print_r($arr1,true)."\n";
	//echo "  arr2: ".print_r($arr2,true)."\n";
	sc_start();
	$res = sc_array_compare($arr1,$arr2);
	sc_end();
	//echo "  returns: $res\n";
	return $res;
}

function sc_array_compare($arr1,$arr2) {
	sc_push('Array');
	$k1 = array_keys($arr1);
	$k2 = array_keys($arr2);
	$keys = array_merge($k1,$k2);
	$keys = array_unique( $keys );
	//echo "sc_array_compare\n";
	//echo "  keys: ".print_r($keys,true)."\n";
	foreach( $keys as $key ) {
		if ( array_key_exists( $key, $arr1 ) ) {
			if ( array_key_exists( $key, $arr2 ) ) {  // both
				$v1 = $arr1[$key];
				$v2 = $arr2[$key];
				$cmp = sc_super_compare($v1,$v2);
				if ( $cmp != 0 ) {
					sc_pop();
					return $cmp;
				}
				continue;  // otherwise fall through
			} else {   // arr1 only
				sc_report("$key only in RHS");
				sc_pop();
				return -1;
			}
		} else {
			if ( array_key_exists( $key, $arr2 ) ) {   // arr2 only
				sc_report("$key only in LHS");
				sc_pop();
				return 1;
			} else {   // arr1 neither
				continue; // fall through to next key
			}
		}
	}
	sc_pop();
	return 0;
}

function super_compare($v1,$v2) {
	sc_start();
	$res = sc_super_compare($v1,$v2);
	sc_end();
	return $res;
}

function sc_super_compare($v1,$v2) {
	//echo "super_compare($v1,$v2)\n";
	$t1 = type_index($v1);
	$t2 = type_index($v2);
	if ( $t1 < $t2 ) {
		sc_report("LHS type ($t1) < RHS type ($t2)");
		return -1;
	}
	if ( $t2 < $t1 ) {
		sc_report("LHS type ($t1) > RHS type ($t2)");
		return 1;
	}
	switch( gettype($v1) ) {
		case "NULL":
				return 0;
				break;
		case "boolean":
				if ( $v1 === $v2 ) return 0;
				sc_report("boolean LHS ($v1) != RHS ($v2)");
				if ( $v1 === false ) return -1;
				return 1;
		case "integer": case "double":
				if ( $v1 < $v2 ) {
					sc_report("number LHS ($v1) < RHS ($v2)");
					return -1;
				}
				if ( $v1 > $v2 ) {
					sc_report("number LHS ($v1) > RHS ($v2)");
					return 1;
				}
				return 0;
		case "string":
				if ( $__sc_ignore_spaces ) {
					$v1 = preg_replace('/\\s+/',' ',$v1);
					$v2 = preg_replace('/\\s+/',' ',$v2);
				}
				$res = strcmp($v1,$v2);
				if ( $res != 0 ) {
					sc_report("string LHS ($v1) != RHS ($v2)");
				}
				return $res;
		case "array":
				return sc_array_compare($v1,$v2);
		case "object":
				return sc_object_compare($v1,$v2);
		default:
				return 0;
	}
}

function super_sort(&$arr) {
	return usort($arr,'super_compare');
}





?>